%% This file is a copy of supervisor.erl from the R16B Erlang/OTP
%% distribution, with the following modifications:
%%
%% 1) the module name is supervisor2
%%
%% 2) a find_child/2 utility function has been added
%%
%% 3) Added an 'intrinsic' restart type. Like the transient type, this
%%    type means the child should only be restarted if the child exits
%%    abnormally. Unlike the transient type, if the child exits
%%    normally, the supervisor itself also exits normally. If the
%%    child is a supervisor and it exits normally (i.e. with reason of
%%    'shutdown') then the child's parent also exits normally.
%%
%% 4) child specifications can contain, as the restart type, a tuple
%%    {permanent, Delay} | {transient, Delay} | {intrinsic, Delay}
%%    where Delay >= 0 (see point (4) below for intrinsic). The delay,
%%    in seconds, indicates what should happen if a child, upon being
%%    restarted, exceeds the MaxT and MaxR parameters. Thus, if a
%%    child exits, it is restarted as normal. If it exits sufficiently
%%    quickly and often to exceed the boundaries set by the MaxT and
%%    MaxR parameters, and a Delay is specified, then rather than
%%    stopping the supervisor, the supervisor instead continues and
%%    tries to start up the child again, Delay seconds later.
%%
%%    Note that if a child is delay-restarted this will reset the
%%    count of restarts towrds MaxR and MaxT. This matters if MaxT >
%%    Delay, since otherwise we would fail to restart after the delay.
%%
%%    Sometimes, you may wish for a transient or intrinsic child to
%%    exit abnormally so that it gets restarted, but still log
%%    nothing. gen_server will log any exit reason other than
%%    'normal', 'shutdown' or {'shutdown', _}. Thus the exit reason of
%%    {'shutdown', 'restart'} is interpreted to mean you wish the
%%    child to be restarted according to the delay parameters, but
%%    gen_server will not log the error. Thus from gen_server's
%%    perspective it's a normal exit, whilst from supervisor's
%%    perspective, it's an abnormal exit.
%%
%% 5) normal, and {shutdown, _} exit reasons are all treated the same
%%    (i.e. are regarded as normal exits)
%%
%% All modifications are (C) 2010-2013 GoPivotal, Inc.
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
-module(supervisor2).

-behaviour(gen_server).

%% External exports
-export([start_link/2, start_link/3,
	 start_child/2, restart_child/2,
	 delete_child/2, terminate_child/2,
	 which_children/1, count_children/1,
	 find_child/2, check_childspecs/1]).

%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).
-export([try_again_restart/3]).

%%--------------------------------------------------------------------------
-ifdef(use_specs).
-export_type([child_spec/0, startchild_ret/0, strategy/0, sup_name/0]).
-endif.
%%--------------------------------------------------------------------------

-ifdef(use_specs).
-type child()    :: 'undefined' | pid().
-type child_id() :: term().
-type mfargs()   :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
-type modules()  :: [module()] | 'dynamic'.
-type delay()    :: non_neg_integer().
-type restart()  :: 'permanent' | 'transient' | 'temporary' | 'intrinsic' | {'permanent', delay()} | {'transient', delay()} | {'intrinsic', delay()}.
-type shutdown() :: 'brutal_kill' | timeout().
-type worker()   :: 'worker' | 'supervisor'.
-type sup_name() :: {'local', Name :: atom()} | {'global', Name :: atom()}.
-type sup_ref()  :: (Name :: atom())
                  | {Name :: atom(), Node :: node()}
                  | {'global', Name :: atom()}
                  | pid().
-type child_spec() :: {Id :: child_id(),
                       StartFunc :: mfargs(),
                       Restart :: restart(),
                       Shutdown :: shutdown(),
                       Type :: worker(),
                       Modules :: modules()}.

-type strategy() :: 'one_for_all' | 'one_for_one'
                  | 'rest_for_one' | 'simple_one_for_one'.
-endif.

%%--------------------------------------------------------------------------
%% supervisor进程的子进程信息
-ifdef(use_specs).
-record(child, {% pid is undefined when child is not running
				pid = undefined :: child() | {restarting,pid()} | [pid()],
				name            :: child_id(),
				mfargs          :: mfargs(),
				restart_type    :: restart(),
				shutdown        :: shutdown(),
				child_type      :: worker(),
				modules = []    :: modules()}).
-type child_rec() :: #child{}.
-else.
-record(child, {
				pid = undefined,
				name,
				mfargs,
				restart_type,
				shutdown,
				child_type,
				modules = []}).
-endif.


-define(DICT, dict).
-define(SETS, sets).
-define(SET, set).


%% supervisor进程的状态信息
-ifdef(use_specs).
-record(state, {name,
				strategy               :: strategy(),
				children = []          :: [child_rec()],
				dynamics               :: ?DICT:?DICT() | ?SET:?SET(),
				intensity              :: non_neg_integer(),
				period                 :: pos_integer(),
				restarts = [],
				module,
				args}).
-type state() :: #state{}.
-else.
-record(state, {name,
				strategy,
				children = [],
				dynamics,
				intensity,
				period,
				restarts = [],
				module,
				args}).
-endif.

%% 判断supervisor是否是simple_one_for_one启动策略
-define(is_simple(State), State#state.strategy =:= simple_one_for_one).


%% 判断是否是permanent或者是{permanent, 2}
-define(is_permanent(R), ((R =:= permanent) orelse
							  (is_tuple(R) andalso
								   tuple_size(R) == 2 andalso
								   element(1, R) =:= permanent))).
%% 判断是否是{shutdown, restart}
-define(is_explicit_restart(R),
		R == {shutdown, restart}).


-ifdef(use_specs).
-callback init(Args :: term()) ->
    {ok, {{RestartStrategy :: strategy(),
           MaxR            :: non_neg_integer(),
           MaxT            :: non_neg_integer()},
           [ChildSpec :: child_spec()]}}
    | ignore.
-else.

-export([behaviour_info/1]).

%% 定义supervisor2应用行为
behaviour_info(callbacks) ->
    [{init,1}];
behaviour_info(_Other) ->
    undefined.

-endif.
-define(restarting(_Pid_), {restarting, _Pid_}).

%%% ---------------------------------------------------
%%% This is a general process supervisor built upon gen_server.erl.
%%% Servers/processes should/could also be built using gen_server.erl.
%%% SupName = {local, atom()} | {global, atom()}.
%%% ---------------------------------------------------
-ifdef(use_specs).
-type startlink_err() :: {'already_started', pid()}
                         | {'shutdown', term()}
                         | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.

-spec start_link(Module, Args) -> startlink_ret() when
      Module :: module(),
      Args :: term().

-endif.
%% 监督进程的开始入口
start_link(Mod, Args) ->
	gen_server:start_link(?MODULE, {self, Mod, Args}, []).
 

-ifdef(use_specs).
-spec start_link(SupName, Module, Args) -> startlink_ret() when
      SupName :: sup_name(),
      Module :: module(),
      Args :: term().
-endif.
%% 监督进程的开始入口
start_link(SupName, Mod, Args) ->
	gen_server:start_link(SupName, ?MODULE, {SupName, Mod, Args}, []).
 
%%% ---------------------------------------------------
%%% Interface functions.
%%% ---------------------------------------------------
-ifdef(use_specs).
-type startchild_err() :: 'already_present'
			| {'already_started', Child :: child()} | term().
-type startchild_ret() :: {'ok', Child :: child()}
                        | {'ok', Child :: child(), Info :: term()}
			| {'error', startchild_err()}.

-spec start_child(SupRef, ChildSpec) -> startchild_ret() when
      SupRef :: sup_ref(),
      ChildSpec :: child_spec() | (List :: [term()]).
-endif.
%% 启动一个子进程根据传入的子进程配置参数
start_child(Supervisor, ChildSpec) ->
	call(Supervisor, {start_child, ChildSpec}).


-ifdef(use_specs).
-spec restart_child(SupRef, Id) -> Result when
      SupRef :: sup_ref(),
      Id :: child_id(),
      Result :: {'ok', Child :: child()}
              | {'ok', Child :: child(), Info :: term()}
              | {'error', Error},
      Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one' |
	       term().
-endif.
%% 暴露给外部的重启子进程的接口
restart_child(Supervisor, Name) ->
	call(Supervisor, {restart_child, Name}).


-ifdef(use_specs).
-spec delete_child(SupRef, Id) -> Result when
      SupRef :: sup_ref(),
      Id :: child_id(),
      Result :: 'ok' | {'error', Error},
      Error :: 'running' | 'restarting' | 'not_found' | 'simple_one_for_one'.
-endif.
%% 删除子进程
delete_child(Supervisor, Name) ->
	call(Supervisor, {delete_child, Name}).

%%-----------------------------------------------------------------
%% Func: terminate_child/2
%% Returns: ok | {error, Reason}
%%          Note that the child is *always* terminated in some
%%          way (maybe killed).
%%-----------------------------------------------------------------
-ifdef(use_specs).
-spec terminate_child(SupRef, Id) -> Result when
      SupRef :: sup_ref(),
      Id :: pid() | child_id(),
      Result :: 'ok' | {'error', Error},
      Error :: 'not_found' | 'simple_one_for_one'.
-endif.
%% 终止子进程
terminate_child(Supervisor, Name) ->
	call(Supervisor, {terminate_child, Name}).


-ifdef(use_specs).
-spec which_children(SupRef) -> [{Id,Child,Type,Modules}] when
      SupRef :: sup_ref(),
      Id :: child_id() | undefined,
      Child :: child() | 'restarting',
      Type :: worker(),
      Modules :: modules().
-endif.
%% 拿到监督进程的所有子进程的信息
which_children(Supervisor) ->
	call(Supervisor, which_children).


-ifdef(use_specs).
-spec count_children(SupRef) -> PropListOfCounts when
      SupRef :: sup_ref(),
      PropListOfCounts :: [Count],
      Count :: {specs, ChildSpecCount :: non_neg_integer()}
             | {active, ActiveProcessCount :: non_neg_integer()}
             | {supervisors, ChildSupervisorCount :: non_neg_integer()}
             |{workers, ChildWorkerCount :: non_neg_integer()}.
-endif.
%% 拿到监督进程的子进程的梳理
count_children(Supervisor) ->
	call(Supervisor, count_children).


-ifdef(use_specs).
-spec find_child(Supervisor, Name) -> [pid()] when
      Supervisor :: sup_ref(),
      Name :: child_id().
-endif.
%% 查找名字为Name的子进程
find_child(Supervisor, Name) ->
	[Pid || {Name1, Pid, _Type, _Modules} <- which_children(Supervisor),
			Name1 =:= Name].


call(Supervisor, Req) ->
	gen_server:call(Supervisor, Req, infinity).


-ifdef(use_specs).
-spec check_childspecs(ChildSpecs) -> Result when
      ChildSpecs :: [child_spec()],
      Result :: 'ok' | {'error', Error :: term()}.
-endif.
%% 检查子进程的配置参数的合法性
check_childspecs(ChildSpecs) when is_list(ChildSpecs) ->
	case check_startspec(ChildSpecs) of
		{ok, _} -> ok;
		Error -> {error, Error}
	end;
check_childspecs(X) -> {error, {badarg, X}}.

%%%-----------------------------------------------------------------
%%% Called by timer:apply_after from restart/2
-ifdef(use_specs).
-spec try_again_restart(SupRef, Child, Reason) -> ok when
      SupRef :: sup_ref(),
      Child :: child_id() | pid(),
      Reason :: term().
-endif.
%% 再一次重启
try_again_restart(Supervisor, Child, Reason) ->
	cast(Supervisor, {try_again_restart, Child, Reason}).


cast(Supervisor, Req) ->
	gen_server:cast(Supervisor, Req).

%%% ---------------------------------------------------
%%% 
%%% Initialize the supervisor.
%%% 
%%% ---------------------------------------------------
-ifdef(use_specs).
-type init_sup_name() :: sup_name() | 'self'.

-type stop_rsn() :: {'shutdown', term()}
                  | {'bad_return', {module(),'init', term()}}
                  | {'bad_start_spec', term()}
                  | {'start_spec', term()}
                  | {'supervisor_data', term()}.

-spec init({init_sup_name(), module(), [term()]}) ->
        {'ok', state()} | 'ignore' | {'stop', stop_rsn()}.
-endif.
%% supervisor进程的回调初始化函数
init({SupName, Mod, Args}) ->
	process_flag(trap_exit, true),
	case Mod:init(Args) of
		{ok, {SupFlags, StartSpec}} ->
			%% 初始化监督进程的状态
			case init_state(SupName, SupFlags, Mod, Args) of
				{ok, State} when ?is_simple(State) ->
					%% 子进程是动态启动策略
					init_dynamic(State, StartSpec);
				{ok, State} ->
					%% 非动态启动策略
					init_children(State, StartSpec);
				Error ->
					{stop, {supervisor_data, Error}}
			end;
		ignore ->
			ignore;
		Error ->
			{stop, {bad_return, {Mod, init, Error}}}
	end.


%% 非动态启动策略的子进程的初始化
init_children(State, StartSpec) ->
	SupName = State#state.name,
	case check_startspec(StartSpec) of
		{ok, Children} ->
			case start_children(Children, SupName) of
				{ok, NChildren} ->
					{ok, State#state{children = NChildren}};
				{error, NChildren, Reason} ->
					terminate_children(NChildren, SupName),
					{stop, {shutdown, Reason}}
			end;
		Error ->
			{stop, {start_spec, Error}}
	end.


%% 子进程动态启动策略初始化
init_dynamic(State, [StartSpec]) ->
	case check_startspec([StartSpec]) of
		{ok, Children} ->
			{ok, State#state{children = Children}};
		Error ->
			{stop, {start_spec, Error}}
	end;
init_dynamic(_State, StartSpec) ->
	{stop, {bad_start_spec, StartSpec}}.

%%-----------------------------------------------------------------
%% Func: start_children/2
%% Args: Children = [child_rec()] in start order
%%       SupName = {local, atom()} | {global, atom()} | {pid(), Mod}
%% Purpose: Start all children.  The new list contains #child's
%%          with pids.
%% Returns: {ok, NChildren} | {error, NChildren, Reason}
%%          NChildren = [child_rec()] in termination order (reversed
%%                        start order)
%%-----------------------------------------------------------------
%% 非动态启动策略的子进程的启动
start_children(Children, SupName) -> start_children(Children, [], SupName).

start_children([Child | Chs], NChildren, SupName) ->
	case do_start_child(SupName, Child) of
		{ok, undefined} when Child#child.restart_type =:= temporary ->
			start_children(Chs, NChildren, SupName);
		{ok, Pid} ->
			start_children(Chs, [Child#child{pid = Pid} | NChildren], SupName);
		{ok, Pid, _Extra} ->
			start_children(Chs, [Child#child{pid = Pid} | NChildren], SupName);
		{error, Reason} ->
			report_error(start_error, Reason, Child, SupName),
			{error, lists:reverse(Chs) ++ [Child | NChildren],
			 {failed_to_start_child,Child#child.name,Reason}}
	end;
start_children([], NChildren, _SupName) ->
	{ok, NChildren}.


%% 实际启动子进程的地方
do_start_child(SupName, Child) ->
	#child{mfargs = {M, F, Args}} = Child,
	case catch apply(M, F, Args) of
		{ok, Pid} when is_pid(Pid) ->
			NChild = Child#child{pid = Pid},
			%% 报告error_logger进程启动的信息(打印日志)
			report_progress(NChild, SupName),
			{ok, Pid};
		{ok, Pid, Extra} when is_pid(Pid) ->
			NChild = Child#child{pid = Pid},
			%% 报告error_logger进程启动的信息(打印日志)
			report_progress(NChild, SupName),
			{ok, Pid, Extra};
		ignore ->
			{ok, undefined};
		{error, What} -> {error, What};
		What -> {error, What}
	end.


%% 执行子进程的函数启动子进程(动态启动类型的监督进程才会调用该接口来启动子进程)
do_start_child_i(M, F, A) ->
	case catch apply(M, F, A) of
		{ok, Pid} when is_pid(Pid) ->
			{ok, Pid};
		{ok, Pid, Extra} when is_pid(Pid) ->
			{ok, Pid, Extra};
		ignore ->
			{ok, undefined};
		{error, Error} ->
			{error, Error};
		What ->
			{error, What}
	end.

%%% ---------------------------------------------------
%%% 
%%% Callback functions.
%%% 
%%% ---------------------------------------------------
-ifdef(use_specs).
-type call() :: 'which_children' | 'count_children' | {_, _}.	% XXX: refine
-spec handle_call(call(), term(), state()) -> {'reply', term(), state()}.
-endif.
%% 动态启动子进程的消息处理
handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
	Child = hd(State#state.children),
	#child{mfargs = {M, F, A}} = Child,
	Args = A ++ EArgs,
	case do_start_child_i(M, F, Args) of
		{ok, undefined} when Child#child.restart_type =:= temporary ->
			{reply, {ok, undefined}, State};
		{ok, Pid} ->
			NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
			{reply, {ok, Pid}, NState};
		{ok, Pid, Extra} ->
			NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State),
			{reply, {ok, Pid, Extra}, NState};
		What ->
			{reply, What, State}
	end;


%% terminate_child for simple_one_for_one can only be done with pid
handle_call({terminate_child, Name}, _From, State) when not is_pid(Name),
														?is_simple(State) ->
	{reply, {error, simple_one_for_one}, State};


%% 监督进程启动策略为simple_one_for_one终止子进程的时候只能传入Pid
handle_call({terminate_child, Name}, _From, State) ->
	case get_child(Name, State, ?is_simple(State)) of
		{value, Child} ->
			case do_terminate(Child, State#state.name) of
				#child{restart_type = RT} when RT =:= temporary; ?is_simple(State) ->
					{reply, ok, state_del_child(Child, State)};
				NChild ->
					{reply, ok, replace_child(NChild, State)}
			end;
		false ->
			{reply, {error, not_found}, State}
	end;


%%% The requests delete_child and restart_child are invalid(无效) for
%%% simple_one_for_one supervisors.
handle_call({_Req, _Data}, _From, State) when ?is_simple(State) ->
	{reply, {error, simple_one_for_one}, State};


%% 启动非动态启动的子进程
handle_call({start_child, ChildSpec}, _From, State) ->
	case check_childspec(ChildSpec) of
		{ok, Child} ->
			{Resp, NState} = handle_start_child(Child, State),
			{reply, Resp, NState};
		What ->
			{reply, {error, What}, State}
	end;


%% 重启非动态启动的子进程
handle_call({restart_child, Name}, _From, State) ->
	case get_child(Name, State) of
		{value, Child} when Child#child.pid =:= undefined ->
			case do_start_child(State#state.name, Child) of
				{ok, Pid} ->
					NState = replace_child(Child#child{pid = Pid}, State),
					{reply, {ok, Pid}, NState};
				{ok, Pid, Extra} ->
					NState = replace_child(Child#child{pid = Pid}, State),
					{reply, {ok, Pid, Extra}, NState};
				Error ->
					{reply, Error, State}
			end;
		{value, #child{pid = ?restarting(_)}} ->
			{reply, {error, restarting}, State};
		{value, _} ->
			{reply, {error, running}, State};
		_ ->
			{reply, {error, not_found}, State}
	end;


%% 删除非动态启动的子进程
handle_call({delete_child, Name}, _From, State) ->
	case get_child(Name, State) of
		{value, Child} when Child#child.pid =:= undefined ->
			NState = remove_child(Child, State),
			{reply, ok, NState};
		{value, #child{pid = ?restarting(_)}} ->
			{reply, {error, restarting}, State};
		{value, _} ->
			{reply, {error, running}, State};
		_ ->
			{reply, {error, not_found}, State}
	end;


%% 拿到动态启动且重启类型为temporary的所有进程信息
handle_call(which_children, _From, #state{children = [#child{restart_type = temporary,
															 child_type = CT,
															 modules = Mods}]} =
											 State) when ?is_simple(State) ->
	Reply = lists:map(fun(Pid) -> {undefined, Pid, CT, Mods} end,
					  ?SETS:to_list(dynamics_db(temporary, State#state.dynamics))),
	{reply, Reply, State};


%% 拿到动态启动且重启类型为非temporary的所有进程信息
handle_call(which_children, _From, #state{children = [#child{restart_type = RType,
															 child_type = CT,
															 modules = Mods}]} =
											 State) when ?is_simple(State) ->
	Reply = lists:map(fun({?restarting(_), _}) -> {undefined, restarting, CT, Mods};
						 ({Pid, _}) -> {undefined, Pid, CT, Mods} end,
					  ?DICT:to_list(dynamics_db(RType, State#state.dynamics))),
	{reply, Reply, State};


%% 拿到非动态启动类型的所有子进程信息
handle_call(which_children, _From, State) ->
	Resp =
		lists:map(fun(#child{pid = ?restarting(_), name = Name,
							 child_type = ChildType, modules = Mods}) ->
						  {Name, restarting, ChildType, Mods};
					 (#child{pid = Pid, name = Name,
							 child_type = ChildType, modules = Mods}) ->
						  {Name, Pid, ChildType, Mods}
				  end,
				  State#state.children),
	{reply, Resp, State};


%% 拿到动态启动且重启类型为temporary的子进程数量
handle_call(count_children, _From, #state{children = [#child{restart_type = temporary,
															 child_type = CT}]} = State)
  when ?is_simple(State) ->
	{Active, Count} =
		?SETS:fold(fun(Pid, {Alive, Tot}) ->
						   case is_pid(Pid) andalso is_process_alive(Pid) of
							   true -> {Alive + 1, Tot + 1};
							   false ->
								   {Alive, Tot + 1}
						   end
				   end, {0, 0}, dynamics_db(temporary, State#state.dynamics)),
	Reply = case CT of
				supervisor -> [{specs, 1}, {active, Active},
							   {supervisors, Count}, {workers, 0}];
				worker -> [{specs, 1}, {active, Active},
						   {supervisors, 0}, {workers, Count}]
			end,
	{reply, Reply, State};


%% 拿到动态启动且重启类型非temporary的子进程数量
handle_call(count_children, _From,  #state{children = [#child{restart_type = RType,
															  child_type = CT}]} = State)
  when ?is_simple(State) ->
	{Active, Count} =
		?DICT:fold(fun(Pid, _Val, {Alive, Tot}) ->
						   case is_pid(Pid) andalso is_process_alive(Pid) of
							   true ->
								   {Alive + 1, Tot + 1};
							   false ->
								   {Alive, Tot + 1}
						   end
				   end, {0, 0}, dynamics_db(RType, State#state.dynamics)),
	Reply = case CT of
				supervisor -> [{specs, 1}, {active, Active},
							   {supervisors, Count}, {workers, 0}];
				worker -> [{specs, 1}, {active, Active},
						   {supervisors, 0}, {workers, Count}]
			end,
	{reply, Reply, State};


%% 拿到非动态启动监督进程的子进程数量
handle_call(count_children, _From, State) ->
	%% Specs and children are together on the children list...
	{Specs, Active, Supers, Workers} =
		lists:foldl(fun(Child, Counts) ->
							count_child(Child, Counts)
					end, {0, 0, 0, 0}, State#state.children),
	
	%% Reformat counts to a property list.
	Reply = [{specs, Specs}, {active, Active},
			 {supervisors, Supers}, {workers, Workers}],
	{reply, Reply, State}.


count_child(#child{pid = Pid, child_type = worker},
			{Specs, Active, Supers, Workers}) ->
	case is_pid(Pid) andalso is_process_alive(Pid) of
		true ->  {Specs + 1, Active + 1, Supers, Workers + 1};
		false -> {Specs + 1, Active, Supers, Workers + 1}
	end;
count_child(#child{pid = Pid, child_type = supervisor},
			{Specs, Active, Supers, Workers}) ->
	case is_pid(Pid) andalso is_process_alive(Pid) of
		true ->  {Specs + 1, Active + 1, Supers + 1, Workers};
		false -> {Specs + 1, Active, Supers + 1, Workers}
	end.


%%% If a restart attempt failed, this message is sent via
%%% timer:apply_after(0,...) in order to give gen_server the chance to
%%% check it's inbox before trying again.
-ifdef(use_specs).
-spec handle_cast({try_again_restart, child_id() | pid(), term()}, state()) ->
			 {'noreply', state()} | {stop, shutdown, state()}.
-endif.
%% 动态启动类型的监督进程子进程的重启
handle_cast({try_again_restart, Pid, Reason}, #state{children = [Child]} = State)
  when ?is_simple(State) ->
	RT = Child#child.restart_type,
	RPid = restarting(Pid),
	case dynamic_child_args(RPid, dynamics_db(RT, State#state.dynamics)) of
		{ok, Args} ->
			{M, F, _} = Child#child.mfargs,
			NChild = Child#child{pid = RPid, mfargs = {M, F, Args}},
			try_restart(Child#child.restart_type, Reason, NChild, State);
		error ->
			{noreply, State}
	end;


%% 非动态启动类型的监督进程子进程的重启
handle_cast({try_again_restart, Name, Reason}, State) ->
	%% we still support >= R12-B3 in which lists:keyfind/3 doesn't exist
	case lists:keysearch(Name, #child.name, State#state.children) of
		{value, Child = #child{pid = ?restarting(_), restart_type = RestartType}} ->
			try_restart(RestartType, Reason, Child, State);
		_ ->
			{noreply,State}
	end.

%%
%% Take care of terminated children.
%%
-ifdef(use_specs).
-spec handle_info(term(), state()) ->
        {'noreply', state()} | {'stop', 'shutdown', state()}.
-endif.
%% 有子进程死亡
handle_info({'EXIT', Pid, Reason}, State) ->
	case restart_child(Pid, Reason, State) of
		{ok, State1} ->
			{noreply, State1};
		{shutdown, State1} ->
			{stop, shutdown, State1}
	end;


%% 延时重启的消息到达后，把重启列表清空
handle_info({delayed_restart, {RestartType, Reason, Child}}, State)
  when ?is_simple(State) ->
	try_restart(RestartType, Reason, Child, State#state{restarts = []});  %% [1]
handle_info({delayed_restart, {RestartType, Reason, Child}}, State) ->
	case get_child(Child#child.name, State) of
		{value, Child1} ->
			try_restart(RestartType, Reason, Child1,
						State#state{restarts = []}); %% [1]
		_What ->
			{noreply, State}
	end;
%% [1] When we receive a delayed_restart message we want to reset the
%% restarts field since otherwise the MaxT might not have elapsed and
%% we would just delay again and again. Since a common use of the
%% delayed restart feature is for MaxR = 1, MaxT = some huge number
%% (so that we don't end up bouncing around in non-delayed restarts)
%% this is important.
%% 监督进程不能够处理的消息
handle_info(Msg, State) ->
    error_logger:error_msg("Supervisor received unexpected message: ~p~n", 
			   [Msg]),
    {noreply, State}.

%%
%% Terminate this server.
%%
-ifdef(use_specs).
-spec terminate(term(), state()) -> 'ok'.
-endif.
%% 监督进程的停止回调
terminate(_Reason, #state{children=[Child]} = State) when ?is_simple(State) ->
    terminate_dynamic_children(Child, dynamics_db(Child#child.restart_type,
                                                  State#state.dynamics),
                               State#state.name);
terminate(_Reason, State) ->
    terminate_children(State#state.children, State#state.name).

%%
%% Change code for the supervisor.
%% Call the new call-back module and fetch the new start specification.
%% Combine the new spec. with the old. If the new start spec. is
%% not valid the code change will not succeed.
%% Use the old Args as argument to Module:init/1.
%% NOTE: This requires that the init function of the call-back module
%%       does not have any side effects.
%%
-ifdef(use_specs).
-spec code_change(term(), state(), term()) ->
        {'ok', state()} | {'error', term()}.
-endif.
%% 代码改变的回调处理
code_change(_, State, _) ->
	case (State#state.module):init(State#state.args) of
		{ok, {SupFlags, StartSpec}} ->
			case catch check_flags(SupFlags) of
				ok ->
					{Strategy, MaxIntensity, Period} = SupFlags,
					update_childspec(State#state{strategy = Strategy,
												 intensity = MaxIntensity,
												 period = Period},
												StartSpec);
				Error ->
					{error, Error}
			end;
		ignore ->
			{ok, State};
		Error ->
			Error
	end.


%% 检查监督进程的参数
check_flags({Strategy, MaxIntensity, Period}) ->
	validStrategy(Strategy),
	validIntensity(MaxIntensity),
	validPeriod(Period),
	ok;
check_flags(What) ->
	{bad_flags, What}.


update_childspec(State, StartSpec) when ?is_simple(State) ->
	case check_startspec(StartSpec) of
		{ok, [Child]} ->
			{ok, State#state{children = [Child]}};
		Error ->
			{error, Error}
	end;
update_childspec(State, StartSpec) ->
	case check_startspec(StartSpec) of
		{ok, Children} ->
			OldC = State#state.children, % In reverse start order !
			NewC = update_childspec1(OldC, Children, []),
			{ok, State#state{children = NewC}};
		Error ->
			{error, Error}
	end.


%% 更新最新的子进程配置
update_childspec1([Child | OldC], Children, KeepOld) ->
	case update_chsp(Child, Children) of
		{ok,NewChildren} ->
			update_childspec1(OldC, NewChildren, KeepOld);
		false ->
			update_childspec1(OldC, Children, [Child|KeepOld])
	end;
update_childspec1([], Children, KeepOld) ->
	%% Return them in (kept) reverse start order.
	lists:reverse(Children ++ KeepOld).


update_chsp(OldCh, Children) ->
	case lists:map(fun(Ch) when OldCh#child.name =:= Ch#child.name ->
						   Ch#child{pid = OldCh#child.pid};
					  (Ch) ->
						   Ch
				   end,
				   Children) of
		Children ->
			false;  % OldCh not found in new spec.
		NewC ->
			{ok, NewC}
	end.
    
%%% ---------------------------------------------------
%%% Start a new child.
%%% ---------------------------------------------------
%% 处理启动非动态的子进程消息
handle_start_child(Child, State) ->
	case get_child(Child#child.name, State) of
		false ->
			case do_start_child(State#state.name, Child) of
				{ok, undefined} when Child#child.restart_type =:= temporary ->
					{{ok, undefined}, State};
				{ok, Pid} ->
					{{ok, Pid}, save_child(Child#child{pid = Pid}, State)};
				{ok, Pid, Extra} ->
					{{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)};
				{error, What} ->
					{{error, {What, Child}}, State}
			end;
		{value, OldChild} when is_pid(OldChild#child.pid) ->
			{{error, {already_started, OldChild#child.pid}}, State};
		{value, _OldChild} ->
			{{error, already_present}, State}
	end.

%%% ---------------------------------------------------
%%% Restart. A process has terminated.
%%% Returns: {ok, state()} | {shutdown, state()}
%%% ---------------------------------------------------
%% 动态启动类型的监督进程重启子进程
restart_child(Pid, Reason, #state{children = [Child]} = State) when ?is_simple(State) ->
	RestartType = Child#child.restart_type,
	case dynamic_child_args(Pid, dynamics_db(RestartType, State#state.dynamics)) of
		{ok, Args} ->
			{M, F, _} = Child#child.mfargs,
			NChild = Child#child{pid = Pid, mfargs = {M, F, Args}},
			do_restart(RestartType, Reason, NChild, State);
		error ->
			{ok, State}
	end;


%% 非动态启动类型的监督进程重启子进程
restart_child(Pid, Reason, State) ->
	Children = State#state.children,
	%% we still support >= R12-B3 in which lists:keyfind/3 doesn't exist
	case lists:keysearch(Pid, #child.pid, Children) of
		{value, #child{restart_type = RestartType} = Child} ->
			do_restart(RestartType, Reason, Child, State);
		false ->
			{ok, State}
	end.


try_restart(RestartType, Reason, Child, State) ->
	case handle_restart(RestartType, Reason, Child, State) of
		{ok, NState}       -> {noreply, NState};
		{shutdown, State2} -> {stop, shutdown, State2}
	end.


do_restart(RestartType, Reason, Child, State) ->
	maybe_report_error(RestartType, Reason, Child, State),
	handle_restart(RestartType, Reason, Child, State).


maybe_report_error(permanent, Reason, Child, State) ->
	report_child_termination(Reason, Child, State);
maybe_report_error({permanent, _}, Reason, Child, State) ->
	report_child_termination(Reason, Child, State);
maybe_report_error(_Type, Reason, Child, State) ->
	case is_abnormal_termination(Reason) of
		true  -> report_child_termination(Reason, Child, State);
		false -> ok
	end.


report_child_termination(Reason, Child, State) ->
	report_error(child_terminated, Reason, Child, State#state.name).


%% permanent类型遇到任何错误导致进程终止就会重启
handle_restart(permanent, _Reason, Child, State) ->
	restart(Child, State);
%%  只有进程异常终止的时候会被重启
handle_restart(transient, Reason, Child, State) ->
	restart_if_explicit_or_abnormal(fun restart/2,
									fun delete_child_and_continue/2,
									Reason, Child, State);
%% 但intrinsic如果child非正常退出，supervisor也会退出并删除其他所有children。
handle_restart(intrinsic, Reason, Child, State) ->
	restart_if_explicit_or_abnormal(fun restart/2,
									fun delete_child_and_stop/2,
									Reason, Child, State);
%% 进程永远都不会被重启
handle_restart(temporary, _Reason, Child, State) ->
	delete_child_and_continue(Child, State);
handle_restart({permanent, _Delay} = Restart, Reason, Child, State) ->
	do_restart_delay(Restart, Reason, Child, State);
handle_restart({transient, _Delay} = Restart, Reason, Child, State) ->
	restart_if_explicit_or_abnormal(defer_to_restart_delay(Restart, Reason),
									fun delete_child_and_continue/2,
									Reason, Child, State);
handle_restart({intrinsic, _Delay} = Restart, Reason, Child, State) ->
	restart_if_explicit_or_abnormal(defer_to_restart_delay(Restart, Reason),
									fun delete_child_and_stop/2,
									Reason, Child, State).


%% 如果是异常终止则重启，否则删除该子进程
restart_if_explicit_or_abnormal(RestartHow, Otherwise, Reason, Child, State) ->
	case ?is_explicit_restart(Reason) orelse is_abnormal_termination(Reason) of
		true  -> RestartHow(Child, State);
		false -> Otherwise(Child, State)
	end.


defer_to_restart_delay(Restart, Reason) ->
	fun(Child, State) -> do_restart_delay(Restart, Reason, Child, State) end.


delete_child_and_continue(Child, State) ->
	{ok, state_del_child(Child, State)}.


%% 删除子进程同时自己终止
delete_child_and_stop(Child, State) ->
	{shutdown, state_del_child(Child, State)}.


is_abnormal_termination(normal)        -> false;
is_abnormal_termination(shutdown)      -> false;
is_abnormal_termination({shutdown, _}) -> false;
is_abnormal_termination(_Other)        -> true.


%% 延时重启(RabbitMQ的supervisor2中增加的部分)
do_restart_delay({RestartType, Delay}, Reason, Child, State) ->
	case add_restart(State) of
		{ok, NState} ->
			maybe_restart(NState#state.strategy, Child, NState);
		{terminate, _NState} ->
			%% we've reached the max restart intensity, but the
			%% add_restart will have added to the restarts
			%% field. Given we don't want to die here, we need to go
			%% back to the old restarts field otherwise we'll never
			%% attempt to restart later, which is why we ignore
			%% NState for this clause.
			_TRef = erlang:send_after(trunc(Delay * 1000), self(),
									  {delayed_restart,
									   {{RestartType, Delay}, Reason, Child}}),
			{ok, state_del_child(Child, State)}
	end.


restart(Child, State) ->
	case add_restart(State) of
		{ok, NState} ->
			maybe_restart(NState#state.strategy, Child, NState);
		{terminate, NState} ->
			report_error(shutdown, reached_max_restart_intensity,
						 Child, State#state.name),
			{shutdown, remove_child(Child, NState)}
	end.


maybe_restart(Strategy, Child, State) ->
	case restart(Strategy, Child, State) of
		{try_again, Reason, NState2} ->
			%% Leaving control back to gen_server before
			%% trying again. This way other incoming requsts
			%% for the supervisor can be handled - e.g. a
			%% shutdown request for the supervisor or the
			%% child.
			Id = if ?is_simple(State) -> Child#child.pid;
					true -> Child#child.name
				 end,
			timer:apply_after(0, ?MODULE, try_again_restart, [self(), Id, Reason]),
			{ok, NState2};
		Other ->
			Other
	end.


%% 动态启动的监督进程启动子进程
restart(simple_one_for_one, Child, State) ->
	#child{pid = OldPid, mfargs = {M, F, A}} = Child,
	Dynamics = ?DICT:erase(OldPid, dynamics_db(Child#child.restart_type,
											   State#state.dynamics)),
	case do_start_child_i(M, F, A) of
		{ok, Pid} ->
			NState = State#state{dynamics = ?DICT:store(Pid, A, Dynamics)},
			{ok, NState};
		{ok, Pid, _Extra} ->
			NState = State#state{dynamics = ?DICT:store(Pid, A, Dynamics)},
			{ok, NState};
		{error, Error} ->
			NState = State#state{dynamics = ?DICT:store(restarting(OldPid), A,
														Dynamics)},
			report_error(start_error, Error, Child, State#state.name),
			{try_again, Error, NState}
	end;
%% supervisor启动时就启动所有children，一旦一个child挂了，supervisor只去重启这一个child process，不影响其他children
restart(one_for_one, Child, State) ->
	OldPid = Child#child.pid,
	case do_start_child(State#state.name, Child) of
		{ok, Pid} ->
			NState = replace_child(Child#child{pid = Pid}, State),
			{ok, NState};
		{ok, Pid, _Extra} ->
			NState = replace_child(Child#child{pid = Pid}, State),
			{ok, NState};
		{error, Reason} ->
			NState = replace_child(Child#child{pid = restarting(OldPid)}, State),
			report_error(start_error, Reason, Child, State#state.name),
			{try_again, Reason, NState}
	end;
%% supervisor启动时就启动所有children，一旦一个child挂了，supervisor重启在这个child之后声明的所有children
restart(rest_for_one, Child, State) ->
	{ChAfter, ChBefore} = split_child(Child#child.pid, State#state.children),
	ChAfter2 = terminate_children(ChAfter, State#state.name),
	case start_children(ChAfter2, State#state.name) of
		{ok, ChAfter3} ->
			{ok, State#state{children = ChAfter3 ++ ChBefore}};
		{error, ChAfter3, Reason} ->
			NChild = Child#child{pid=restarting(Child#child.pid)},
			NState = State#state{children = ChAfter3 ++ ChBefore},
			{try_again, Reason, replace_child(NChild,NState)}
	end;
%% supervisor启动时就启动所有children，一旦一个child挂了，supervisor重启所有children processes
restart(one_for_all, Child, State) ->
	Children1 = del_child(Child#child.pid, State#state.children),
	Children2 = terminate_children(Children1, State#state.name),
	case start_children(Children2, State#state.name) of
		{ok, NChs} ->
			{ok, State#state{children = NChs}};
		{error, NChs, Reason} ->
			NChild = Child#child{pid=restarting(Child#child.pid)},
			NState = State#state{children = NChs},
			{try_again, Reason, replace_child(NChild,NState)}
	end.


restarting(Pid) when is_pid(Pid) -> ?restarting(Pid);
restarting(RPid) -> RPid.

%%-----------------------------------------------------------------
%% Func: terminate_children/2
%% Args: Children = [child_rec()] in termination order
%%       SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
%% Returns: NChildren = [child_rec()] in
%%          startup order (reversed termination order)
%%-----------------------------------------------------------------
terminate_children(Children, SupName) ->
    terminate_children(Children, SupName, []).

%% Temporary children should not be restarted and thus should
%% be skipped when building the list of terminated children, although
%% we do want them to be shut down as many functions from this module
%% use this function to just clear everything.
terminate_children([Child = #child{restart_type=temporary} | Children], SupName, Res) ->
	do_terminate(Child, SupName),
	terminate_children(Children, SupName, Res);
terminate_children([Child | Children], SupName, Res) ->
	NChild = do_terminate(Child, SupName),
	terminate_children(Children, SupName, [NChild | Res]);
terminate_children([], _SupName, Res) ->
	Res.


%% 停止子进程
do_terminate(Child, SupName) when is_pid(Child#child.pid) ->
	case shutdown(Child#child.pid, Child#child.shutdown) of
		ok ->
			ok;
		{error, normal} when not ?is_permanent(Child#child.restart_type) ->
			ok;
		{error, OtherReason} ->
			report_error(shutdown_error, OtherReason, Child, SupName)
	end,
	Child#child{pid = undefined};
do_terminate(Child, _SupName) ->
	Child#child{pid = undefined}.

%%-----------------------------------------------------------------
%% Shutdowns a child. We must check the EXIT value 
%% of the child, because it might have died with another reason than
%% the wanted. In that case we want to report the error. We put a 
%% monitor on the child an check for the 'DOWN' message instead of 
%% checking for the 'EXIT' message, because if we check the 'EXIT' 
%% message a "naughty" child, who does unlink(Sup), could hang the 
%% supervisor. 
%% Returns: ok | {error, OtherReason}  (this should be reported)
%%-----------------------------------------------------------------
shutdown(Pid, brutal_kill) ->
	case monitor_child(Pid) of
		ok ->
			exit(Pid, kill),
			receive
				{'DOWN', _MRef, process, Pid, killed} ->
					ok;
				{'DOWN', _MRef, process, Pid, OtherReason} ->
					{error, OtherReason}
			end;
		{error, Reason} ->      
			{error, Reason}
	end;
shutdown(Pid, Time) ->
	case monitor_child(Pid) of
		ok ->
			exit(Pid, shutdown), %% Try to shutdown gracefully(优雅)
			receive 
				{'DOWN', _MRef, process, Pid, shutdown} ->
					ok;
				{'DOWN', _MRef, process, Pid, OtherReason} ->
					{error, OtherReason}
				after Time ->
					exit(Pid, kill),  %% Force termination.
					receive
						{'DOWN', _MRef, process, Pid, OtherReason} ->
							{error, OtherReason}
					end
			end;
		{error, Reason} ->      
			{error, Reason}
	end.


%% Help function to shutdown/2 switches from link to monitor approach
monitor_child(Pid) ->
	
	%% Do the monitor operation first so that if the child dies 
	%% before the monitoring is done causing a 'DOWN'-message with
	%% reason noproc, we will get the real reason in the 'EXIT'-message
	%% unless a naughty child has already done unlink...
	erlang:monitor(process, Pid),
	unlink(Pid),
	
	receive
		%% If the child dies before the unlik we must empty
		%% the mail-box of the 'EXIT'-message and the 'DOWN'-message.
		{'EXIT', Pid, Reason} -> 
			receive 
				{'DOWN', _, process, Pid, _} ->
					{error, Reason}
			end
		after 0 -> 
			%% If a naughty child did unlink and the child dies before
			%% monitor the result will be that shutdown/2 receives a 
			%% 'DOWN'-message with reason noproc.
			%% If the child should die after the unlink there
			%% will be a 'DOWN'-message with a correct reason
			%% that will be handled in shutdown/2. 
			ok   
	end.


%%-----------------------------------------------------------------
%% Func: terminate_dynamic_children/3
%% Args: Child    = child_rec()
%%       Dynamics = ?DICT() | ?SET()
%%       SupName  = {local, atom()} | {global, atom()} | {pid(),Mod}
%% Returns: ok
%%
%%
%% Shutdown all dynamic children. This happens when the supervisor is
%% stopped. Because the supervisor can have millions of dynamic children, we
%% can have an significative overhead here.
%%-----------------------------------------------------------------
terminate_dynamic_children(Child, Dynamics, SupName) ->
	{Pids, EStack0} = monitor_dynamic_children(Child, Dynamics),
	Sz = ?SETS:size(Pids),
	EStack = case Child#child.shutdown of
				 brutal_kill ->
					 ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
					 wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
				 infinity ->
					 ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
					 wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
				 Time ->
					 ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
					 TRef = erlang:start_timer(Time, self(), kill),
					 wait_dynamic_children(Child, Pids, Sz, TRef, EStack0)
			 end,
	%% Unroll stacked errors and report them
	?DICT:fold(fun(Reason, Ls, _) ->
					   report_error(shutdown_error, Reason,
									Child#child{pid=Ls}, SupName)
			   end, ok, EStack).


monitor_dynamic_children(#child{restart_type=temporary}, Dynamics) ->
	?SETS:fold(fun(P, {Pids, EStack}) ->
					   case monitor_child(P) of
						   ok ->
							   {?SETS:add_element(P, Pids), EStack};
						   {error, normal} ->
							   {Pids, EStack};
						   {error, Reason} ->
							   {Pids, ?DICT:append(Reason, P, EStack)}
					   end
			   end, {?SETS:new(), ?DICT:new()}, Dynamics);
monitor_dynamic_children(#child{restart_type=RType}, Dynamics) ->
	?DICT:fold(fun(P, _, {Pids, EStack}) when is_pid(P) ->
					   case monitor_child(P) of
						   ok ->
							   {?SETS:add_element(P, Pids), EStack};
						   {error, normal} when not ?is_permanent(RType) ->
							   {Pids, EStack};
						   {error, Reason} ->
							   {Pids, ?DICT:append(Reason, P, EStack)}
					   end;
				  (?restarting(_), _, {Pids, EStack}) ->
					   {Pids, EStack}
			   end, {?SETS:new(), ?DICT:new()}, Dynamics).


wait_dynamic_children(_Child, _Pids, 0, undefined, EStack) ->
	EStack;
wait_dynamic_children(_Child, _Pids, 0, TRef, EStack) ->
	%% If the timer has expired before its cancellation, we must empty the
	%% mail-box of the 'timeout'-message.
	erlang:cancel_timer(TRef),
	receive
		{timeout, TRef, kill} ->
			EStack
		after 0 ->
			EStack
	end;
wait_dynamic_children(#child{shutdown=brutal_kill} = Child, Pids, Sz,
					  TRef, EStack) ->
	receive
		{'DOWN', _MRef, process, Pid, killed} ->
			wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
								  TRef, EStack);
		
		{'DOWN', _MRef, process, Pid, Reason} ->
			wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
								  TRef, ?DICT:append(Reason, Pid, EStack))
	end;
wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
					  TRef, EStack) ->
	receive
		{'DOWN', _MRef, process, Pid, shutdown} ->
			wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
								  TRef, EStack);
		
		{'DOWN', _MRef, process, Pid, normal} when not ?is_permanent(RType) ->
			wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
								  TRef, EStack);
		
		{'DOWN', _MRef, process, Pid, Reason} ->
			wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
								  TRef, ?DICT:append(Reason, Pid, EStack));
		
		{timeout, TRef, kill} ->
			?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
			wait_dynamic_children(Child, Pids, Sz-1, undefined, EStack)
	end.

%%-----------------------------------------------------------------
%% Child/State manipulating functions.
%%-----------------------------------------------------------------

%% Note we do not want to save the parameter list for temporary processes as
%% they will not be restarted, and hence we do not need this information.
%% Especially for dynamic children to simple_one_for_one supervisors
%% it could become very costly as it is not uncommon to spawn
%% very many such processes.
%% 子进程重启类型为temporary不会存储它的函数参数，因为该类型的子进程根本不会重启
save_child(#child{restart_type = temporary,
				  mfargs = {M, F, _}} = Child, #state{children = Children} = State) ->
	State#state{children = [Child#child{mfargs = {M, F, undefined}} |Children]};
save_child(Child, #state{children = Children} = State) ->
	State#state{children = [Child |Children]}.


%% 保存动态启动子进程
save_dynamic_child(temporary, Pid, _, #state{dynamics = Dynamics} = State) ->
	State#state{dynamics = ?SETS:add_element(Pid, dynamics_db(temporary, Dynamics))};
save_dynamic_child(RestartType, Pid, Args, #state{dynamics = Dynamics} = State) ->
	State#state{dynamics = ?DICT:store(Pid, Args, dynamics_db(RestartType, Dynamics))}.


%% 根据子进程的重启策略创建不同的数据结构来存储动态启动的子进程
dynamics_db(temporary, undefined) ->
	?SETS:new();
dynamics_db(_, undefined) ->
	?DICT:new();
dynamics_db(_, Dynamics) ->
	Dynamics.


dynamic_child_args(Pid, Dynamics) ->
	case ?SETS:is_set(Dynamics) of
		true ->
			{ok, undefined};
		false ->
			?DICT:find(Pid, Dynamics)
	end.


%% 删除子进程信息
state_del_child(#child{pid = Pid, restart_type = temporary}, State) when ?is_simple(State) ->
	NDynamics = ?SETS:del_element(Pid, dynamics_db(temporary, State#state.dynamics)),
	State#state{dynamics = NDynamics};
state_del_child(#child{pid = Pid, restart_type = RType}, State) when ?is_simple(State) ->
	NDynamics = ?DICT:erase(Pid, dynamics_db(RType, State#state.dynamics)),
	State#state{dynamics = NDynamics};
state_del_child(Child, State) ->
	NChildren = del_child(Child#child.name, State#state.children),
	State#state{children = NChildren}.


%% 非动态子进程的删除
del_child(Name, [Ch = #child{pid = ?restarting(_)} | _] = Chs) when Ch#child.name =:= Name ->
	Chs;
del_child(Name, [Ch | Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
	Chs;
del_child(Name, [Ch | Chs]) when Ch#child.name =:= Name ->
	[Ch#child{pid = undefined} | Chs];
del_child(Pid, [Ch | Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
	Chs;
del_child(Pid, [Ch | Chs]) when Ch#child.pid =:= Pid ->
	[Ch#child{pid = undefined} | Chs];
del_child(Name, [Ch | Chs]) ->
	[Ch | del_child(Name, Chs)];
del_child(_, []) ->
	[].


%% Chs = [S4, S3, Ch, S1, S0]
%% Ret: {[S4, S3, Ch], [S1, S0]}
%% 根据子进程名字为Name的子进程将所有的子进程列表分割为两份
split_child(Name, Chs) ->
	split_child(Name, Chs, []).


split_child(Name, [Ch | Chs], After) when Ch#child.name =:= Name ->
	{lists:reverse([Ch#child{pid = undefined} | After]), Chs};
split_child(Pid, [Ch | Chs], After) when Ch#child.pid =:= Pid ->
	{lists:reverse([Ch#child{pid = undefined} | After]), Chs};
split_child(Name, [Ch | Chs], After) ->
	split_child(Name, Chs, [Ch | After]);
split_child(_, [], After) ->
	{lists:reverse(After), []}.


%% 根据子进程名字拿到子进程信息
get_child(Name, State) ->
	get_child(Name, State, false).
get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) ->
	get_dynamic_child(Pid, State);
get_child(Name, State, _) ->
	lists:keysearch(Name, #child.name, State#state.children).


%% 根据Pid拿到动态启动的类型的子进程信息
get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) ->
	DynamicsDb = dynamics_db(Child#child.restart_type, Dynamics),
	case is_dynamic_pid(Pid, DynamicsDb) of
		true ->
			{value, Child#child{pid = Pid}};
		false ->
			RPid = restarting(Pid),
			case is_dynamic_pid(RPid, DynamicsDb) of
				true ->
					{value, Child#child{pid = RPid}};
				false ->
					case erlang:is_process_alive(Pid) of
						true -> false;
						false -> {value, Child}
					end
			end
	end.


is_dynamic_pid(Pid, Dynamics) ->
	case ?SETS:is_set(Dynamics) of
		true ->
			?SETS:is_element(Pid, Dynamics);
		false ->
			?DICT:is_key(Pid, Dynamics)
	end.


%% 新的子进程信息替换老的子进程信息
replace_child(Child, State) ->
	Chs = do_replace_child(Child, State#state.children),
	State#state{children = Chs}.


%% 实际的替换过程
do_replace_child(Child, [Ch | Chs]) when Ch#child.name =:= Child#child.name ->
	[Child | Chs];
do_replace_child(Child, [Ch | Chs]) ->
	[Ch | do_replace_child(Child, Chs)].


%% 删除非动态启动的子进程信息
remove_child(Child, State) ->
	Chs = lists:keydelete(Child#child.name, #child.name, State#state.children),
	State#state{children = Chs}.

%%-----------------------------------------------------------------
%% Func: init_state/4
%% Args: SupName = {local, atom()} | {global, atom()} | self
%%       Type = {Strategy, MaxIntensity, Period}
%%         Strategy = one_for_one | one_for_all | simple_one_for_one |
%%                    rest_for_one
%%         MaxIntensity = integer() >= 0
%%         Period = integer() > 0
%%       Mod :== atom()
%%       Args :== term()
%% Purpose: Check that Type is of correct type (!)
%% Returns: {ok, state()} | Error
%%-----------------------------------------------------------------
%% 初始化整个监督进程的重启策略
init_state(SupName, Type, Mod, Args) ->
	case catch init_state1(SupName, Type, Mod, Args) of
		{ok, State} ->
			{ok, State};
		Error ->
			Error
	end.


init_state1(SupName, {Strategy, MaxIntensity, Period}, Mod, Args) ->
	%% 判断是否是支持的重启策略
	validStrategy(Strategy),
	%% 判断重启次数是否正确
	validIntensity(MaxIntensity),
	%% 判断重启间隔时间是否正确
	validPeriod(Period),
	{ok, #state{name = supname(SupName, Mod),
				strategy = Strategy,
				intensity = MaxIntensity,
				period = Period,
				module = Mod,
				args = Args}};
init_state1(_SupName, Type, _, _) ->
	{invalid_type, Type}.


validStrategy(simple_one_for_one) -> true;
validStrategy(one_for_one)        -> true;
validStrategy(one_for_all)        -> true;
validStrategy(rest_for_one)       -> true;
validStrategy(What)               -> throw({invalid_strategy, What}).


validIntensity(Max) when is_integer(Max),
						 Max >=  0 -> true;
validIntensity(What)               -> throw({invalid_intensity, What}).


validPeriod(Period) when is_integer(Period),
						 Period > 0 -> true;
validPeriod(What)                   -> throw({invalid_period, What}).


supname(self, Mod) -> {self(), Mod};
supname(N, _)      -> N.

%%% ------------------------------------------------------
%%% Check that the children start specification is valid.
%%% Shall be a six (6) tuple
%%%    {Name, Func, RestartType, Shutdown, ChildType, Modules}
%%% where Name is an atom
%%%       Func is {Mod, Fun, Args} == {atom(), atom(), list()}
%%%       RestartType is permanent | temporary | transient |
%%%                      intrinsic | {permanent, Delay} |
%%%                      {transient, Delay} | {intrinsic, Delay}
%%                       where Delay >= 0
%%%       Shutdown = integer() > 0 | infinity | brutal_kill
%%%       ChildType = supervisor | worker
%%%       Modules = [atom()] | dynamic
%%% Returns: {ok, [child_rec()]} | Error
%%% ------------------------------------------------------
%% 检查子进程配置的合法性(如果合法则返回child数据结构)
check_startspec(Children) -> check_startspec(Children, []).


check_startspec([ChildSpec | T], Res) ->
	case check_childspec(ChildSpec) of
		{ok, Child} ->
			case lists:keymember(Child#child.name, #child.name, Res) of
				true -> {duplicate_child_name, Child#child.name};
				false -> check_startspec(T, [Child | Res])
			end;
		Error -> Error
	end;
check_startspec([], Res) ->
	{ok, lists:reverse(Res)}.


check_childspec({Name, Func, RestartType, Shutdown, ChildType, Mods}) ->
	catch check_childspec(Name, Func, RestartType, Shutdown, ChildType, Mods);
check_childspec(X) -> {invalid_child_spec, X}.


check_childspec(Name, Func, RestartType, Shutdown, ChildType, Mods) ->
	%% 检查子进程名字的合法性
	validName(Name),
	%% 检查执行的函数的合法性
	validFunc(Func),
	%% 检查重启策略的合法性
	validRestartType(RestartType),
	%% 检查子进程的类型的合法性
	validChildType(ChildType),
	%% 检查子进程停止配置的合法性
	validShutdown(Shutdown, ChildType),
	%% 检查模块列表的合法性
	validMods(Mods),
	{ok, #child{name = Name, mfargs = Func, restart_type = RestartType,
				shutdown = Shutdown, child_type = ChildType, modules = Mods}}.


%% 检查子进程的类型的合法性
validChildType(supervisor) -> true;
validChildType(worker) -> true;
validChildType(What) -> throw({invalid_child_type, What}).


%% 检查子进程名字的合法性
validName(_Name) -> true.


%% 检查执行的函数的合法性
validFunc({M, F, A}) when is_atom(M), 
						  is_atom(F), 
						  is_list(A) -> true;
validFunc(Func)                      -> throw({invalid_mfa, Func}).


%% 检查重启策略的合法性
validRestartType(permanent)          -> true;
validRestartType(temporary)          -> true;
validRestartType(transient)          -> true;
validRestartType(intrinsic)          -> true;
validRestartType({permanent, Delay}) -> validDelay(Delay);
validRestartType({intrinsic, Delay}) -> validDelay(Delay);
validRestartType({transient, Delay}) -> validDelay(Delay);
validRestartType(RestartType)        -> throw({invalid_restart_type,
											   RestartType}).


%% 检查延时时间设置的合法性
validDelay(Delay) when is_number(Delay),
					   Delay >= 0 -> true;
validDelay(What)                  -> throw({invalid_delay, What}).


%% 检查子进程停止配置的合法性
validShutdown(Shutdown, _) 
  when is_integer(Shutdown), Shutdown > 0 -> true;
validShutdown(infinity, _)             -> true;
validShutdown(brutal_kill, _)          -> true;
validShutdown(Shutdown, _)             -> throw({invalid_shutdown, Shutdown}).


%% 检查模块列表的合法性
validMods(dynamic) -> true;
validMods(Mods) when is_list(Mods) ->
	lists:foreach(fun(Mod) ->
						  if
							  is_atom(Mod) -> ok;
							  true -> throw({invalid_module, Mod})
						  end
				  end,
				  Mods);
validMods(Mods) -> throw({invalid_modules, Mods}).

%%% ------------------------------------------------------
%%% Add a new restart and calculate if the max restart
%%% intensity has been reached (in that case the supervisor
%%% shall terminate).
%%% All restarts accured inside the period amount of seconds
%%% are kept in the #state.restarts list.
%%% Returns: {ok, State'} | {terminate, State'}
%%% ------------------------------------------------------
%% 增加一个restart到数据里
add_restart(State) ->
	I = State#state.intensity,
	P = State#state.period,
	R = State#state.restarts,
	Now = erlang:now(),
	R1 = add_restart([Now | R], Now, P),
	State1 = State#state{restarts = R1},
	case length(R1) of
		CurI when CurI  =< I ->
			{ok, State1};
		_ ->
			{terminate, State1}
	end.


add_restart([R | Restarts], Now, Period) ->
	case inPeriod(R, Now, Period) of
		true ->
			[R | add_restart(Restarts, Now, Period)];
		_ ->
			[]
	end;
add_restart([], _, _) ->
	[].


inPeriod(Time, Now, Period) ->
	case difference(Time, Now) of
		T when T > Period ->
			false;
		_ ->
			true
	end.

%%
%% Time = {MegaSecs, Secs, MicroSecs} (NOTE: MicroSecs is ignored)
%% Calculate the time elapsed in seconds between two timestamps.
%% If MegaSecs is equal just subtract Secs.
%% Else calculate the Mega difference and add the Secs difference,
%% note that Secs difference can be negative, e.g.
%%      {827, 999999, 676} diff {828, 1, 653753} == > 2 secs.
%%
%% 计算连个now时间戳相差的秒数
difference({TimeM, TimeS, _}, {CurM, CurS, _}) when CurM > TimeM ->
	((CurM - TimeM) * 1000000) + (CurS - TimeS);
difference({_, TimeS, _}, {_, CurS, _}) ->
	CurS - TimeS.

%%% ------------------------------------------------------
%%% Error and progress reporting.
%%% ------------------------------------------------------
%% 监督进程报告子进程错误信息
report_error(Error, Reason, Child, SupName) ->
    ErrorMsg = [{supervisor, SupName},
		{errorContext, Error},
		{reason, Reason},
		{offender, extract_child(Child)}],
    error_logger:error_report(supervisor_report, ErrorMsg).


%% 打包子进程的信息
extract_child(Child) when is_list(Child#child.pid) ->
    [{nb_children, length(Child#child.pid)},
     {name, Child#child.name},
     {mfargs, Child#child.mfargs},
     {restart_type, Child#child.restart_type},
     {shutdown, Child#child.shutdown},
     {child_type, Child#child.child_type}];
extract_child(Child) ->
    [{pid, Child#child.pid},
     {name, Child#child.name},
     {mfargs, Child#child.mfargs},
     {restart_type, Child#child.restart_type},
     {shutdown, Child#child.shutdown},
     {child_type, Child#child.child_type}].


%% 报告error_logger进程启动的信息
report_progress(Child, SupName) ->
	Progress = [{supervisor, SupName},
				{started, extract_child(Child)}],
	error_logger:info_report(progress, Progress).
